#ifndef JOB_H
#define JOB_H

#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

#include <list>

#define FIFO "./SVRFIFO"

#ifndef DEBUG
#define DEBUG
#endif

// #undef DEBUG

#define BUFLEN 100
#define GLOBALFILE "screendump"

enum jobstate { READY, RUNNING, DONE };

enum cmdtype { ENQ = -1, DEQ = -2, STAT = -3 };

/* this is data passed in fifo */
struct jobcmd {
  enum cmdtype type;
  int argnum;
  int owner;
  int defpri;
  char data[BUFLEN];  // parameters seperated by : i.e. colon
};

#define DATALEN sizeof(struct jobcmd)
// #define error_sys printf
#define error_sys puts

size_t strlistlen(char **array) {
  for (int i = 0;; ++i) {
    if (array[i] == NULL) return i;
  }
}
struct jobinfo {
  int jid;            /* job id */
  int pid;            /* process id */
  char **cmdarg;      /* the command & args to execute */
  int defpri;         /* default priority */
  int curpri;         /* current priority */
  int ownerid;        /* the job owner id */
  int wait_time;      /* the time job in waitqueue */
  time_t create_time; /* the time job create */
  int run_time;       /* the time job running */
  jobstate state;     /* job state */
#ifdef _GLIBCXX_LIST
  jobinfo(int job, const jobcmd &jc)
      : jid(job), state(READY), wait_time(0), run_time(0) {
    pid = getpid();
    curpri = defpri = jc.defpri;
    ownerid = jc.owner;
    create_time = time(NULL);
  }
  jobinfo(int job, const jobinfo &ji) { assign(ji); }
  void assign(const jobinfo &ji) {
    this->jid = ji.jid;
    size_t sl = strlistlen(ji.cmdarg);
    this->cmdarg = (char **)sizeof(sizeof(char *) * (sl + 1));
    char *ptr;
    int len = 0;
    for (int i = 0; ptr != NULL; ++i) {
      ptr = ji.cmdarg[i];
      len = strlen(ptr);
      cmdarg[i] = (char *)malloc(len + 1);
      strncpy(cmdarg[i], ptr, len);
      cmdarg[i][len] = 0;
    }
    cmdarg[sl] = NULL;
  }
#endif
};
struct waitqueue;
void freequeue(waitqueue *select);
struct waitqueue { /* forward link list */
#ifdef _GLIBCXX_LIST
  // std::list<waitqueue>::iterator next; /* on need */
  jobinfo *job;
  waitqueue(jobinfo &ji) : job((jobinfo *)malloc(sizeof(jobinfo))) {
    job->assign(ji);
  }
  ~waitqueue() { freequeue(this); }
  waitqueue(std::_List_iterator<waitqueue> &it) : job(it->job) {}
#else
  struct waitqueue *next;
  struct jobinfo *job;
#endif
};

void schedule();
void sig_handler(int sig, siginfo_t *info, void *notused);
int allocjid();
void do_enq(jobcmd enqcmd);
void do_deq(jobcmd deqcmd);
void do_stat();
void updateall();
std::list<waitqueue>::iterator jobselect();
void jobswitch();

template <class T>
void freequeue(T select) {
  for (int i = 0; (select->job->cmdarg)[i] != NULL; ++i) {
    free((select->job->cmdarg)[i]);
    (select->job->cmdarg)[i] = NULL;
  }

  free(select->job->cmdarg);
  free(select->job);
}
void freequeue(std::list<waitqueue>::iterator &select) {
  freequeue<std::list<waitqueue>::iterator>(select);
}
void freequeue(waitqueue *select) { freequeue<waitqueue *>(select); }
#endif
